﻿<?php

//////////////////////////////////////////////////////////////////////////
//
// WikiHiero2 - A PHP convert from text using "Manual for the encoding of
// hieroglyphic texts for computer input" syntax to HTML entities (table and
// images).
//
// Copyright (C) 2004-2010 Guillaume Blanchard (Aoineko)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
//////////////////////////////////////////////////////////////////////////

require_once("wh_MdC/wh_phonemes.php");

define("WH_MDC_TEXT_UNDEFINED",    -1);
define("WH_MDC_TEXT_HIEROGLYPH",    0); // +s
define("WH_MDC_TEXT_COMMENT",       1); // ++
define("WH_MDC_TEXT_TRANSCRIPTION", 2); // +t
define("WH_MDC_TEXT_LATIN_NORMAL",  3); // +l
define("WH_MDC_TEXT_LATIN_ITALIC",  4); // +i
define("WH_MDC_TEXT_LATIN_BOLD",    5); // +b
define("WH_MDC_TEXT_GREEK",         6); // +g
define("WH_MDC_TEXT_COPTIC",        7); // +c

// "copyright 2007 CULTNAT (Center for Documentation of Cultural and Natural Heritage)"

define("WH_MDC_CODE_UNDEFINED",  -1);
define("WH_MDC_CODE_GLYPH",       0);
define("WH_MDC_CODE_GROUP",       1);
define("WH_MDC_CODE_END_OF_PAGE", 2);
define("WH_MDC_CODE_END_OF_LINE", 3);

define("WH_MDC_FLAG_NONE",        0x0000);
define("WH_MDC_FLAG_NUMBER",      0x0001); // number [0-9]
define("WH_MDC_FLAG_ALPHA",       0x0002); // character [a-zA-Z.]
define("WH_MDC_FLAG_OPERATOR",    0x0004); // operator [:-()*]
define("WH_MDC_FLAG_COMMAND",     0x0008); // command [<>$[rb]#[be]]
define("WH_MDC_FLAG_OPTION",      0x0010); // option [#[1234]]

////////////////////////////////////////////////////////////////////////////////
/**
 * Manuel de codage's plugin
 */
class WH_MDC extends WH_Plugin 
{
	protected $document;
	protected $acc;
	protected $depth;
	protected $flag;
	protected $createSection;
	protected $createSentence;
	protected $createWord;

	////////////////////////////////////////////////////////////////////////////////
	/**
	 *
	 */
	public function __construct()
	{
		// Plugin parameters
		$this->RegisterVariable("ParseSyntax",   WH_Variable::Boolean, true);
		$this->RegisterVariable("MdcVersion",    WH_Variable::Enum,    "Strict", array("Strict", "Rosette", "MdC++"));
		
		// Member variables
		$this->document = null;
		$this->acc = "";
		$this->depth = 0;
		$this->flag = 0;
		$this->createSection = true;
		$this->createSentence = true;
		$this->createWord = true;
	}

	public static function CanImport() { return true; }
	public static function CanExport() { return true; }
	
	public static function GetName() { return "Manuel de Codage"; }
	public static function GetId() { return "MdC88"; }
	public static function GetVersion() { return "0.5"; }
	public static function GetDesc($type = WH_Plugin::TypeDefault, $lang = "") { return "Manuel de Codage 1988"; }
	public static function GetCredit($lang = "") { return "Guillaume Blanchard (2004-2010)"; }
	
	static public function IsGardinerCode($text)
	{
		if(strlen($text) < 2)
			return false;

		if(!ctype_upper($text[0]))
			return false;

		if(!ctype_digit($text[1]))
			return false;

		return true; // return true if format is "[A-Z][0-9].*"
	}

	static public function GetGardinerCode(&$str)
	{
		if(isset(WH_MDC_PHONEMES::$data[$str]))
			return WH_MDC_PHONEMES::$data[$str];

		return "";
	}

	////////////////////////////////////////////////////////////////////////////////
	/**
	 * Flush accumulator data into the current area.
	 */
	protected function FlushAccumulator()
	{
		if($this->acc == "")
			return; // Skip process if accumulator is empty

		if($this->document->GetCurrentArea()->GetAttribute(WH_Attribute::Type) == WH_MDC_TEXT_HIEROGLYPH)
			$this->AddHiero($this->acc);
		else
			$this->document->GetCurrentArea()->SetAttribute(WH_Attribute::Content, $this->acc);

		$this->acc = ""; // Empty the accumulator
	}

	////////////////////////////////////////////////////////////////////////////////
	/**
	 * [-:*]
	 */
	protected function ParseOperator(&$str, $op, &$left, &$right)
	{
		$depth = 0;
		for($i=0; $i<strlen($str); $i++)
		{
			if($str[$i] == '(')
				$depth++;
			if($str[$i] == ')')
				$depth--;
			if($depth == 0)
			{
				if($str[$i] == $op)
				{
					$left  = substr($str, 0, $i);
					$right = substr($str, $i+1);
					return true;
				}
			}
		}
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////
	/**
	 * [()]
	 */
	protected function ParseParenthesis(&$str, &$result)
	{
		if(($str[0] == '(') && ($str[strlen($str)-1] == ')'))
		{
			$result = substr($str, 1, strlen($str)-2);
			return true;
		}
		return false;
	}

	protected function SetHieroAttribute(&$node, &$str)
	{
		if(!WH_MDC::IsGardinerCode($str))
		{
			$mdc = WH_MDC::GetGardinerCode($str);
			if($mdc)
			{
				$node->SetAttribute(WH_Attribute::Code, $mdc);
				$node->SetAttribute(WH_Attribute::Phoneme, $str);
			}
			else
				$node->SetAttribute(WH_Attribute::Content, $str);
		}
		else
			$node->SetAttribute(WH_Attribute::Code, $str);
	}

	protected function SetHieroSyntax(&$node)
	{
		if($this->createSection == true)
		{
			$this->document->AddSection();
			$this->createSection = false;
		}
		if($this->createSentence == true)
		{
			$this->document->AddSentence();
			$this->createSentence = false;
		}
		if($this->createWord == true)
		{
			$this->document->AddWord();
			$this->createWord = false;
		}

		if($this->document->GetCurrentSentence()->IsAttributeSet(WH_Attribute::Reference))
			$ref = $this->document->GetCurrentSentence()->GetAttribute(WH_Attribute::Reference)." ".$node->GetAttribute(WH_Attribute::Id);
		else
			$ref = $node->GetAttribute(WH_Attribute::Id);
		$this->document->GetCurrentSentence()->SetAttribute(WH_Attribute::Reference, $ref);
		
		if($this->document->GetCurrentWord()->IsAttributeSet(WH_Attribute::Reference))
			$ref = $this->document->GetCurrentWord()->GetAttribute(WH_Attribute::Reference)." ".$node->GetAttribute(WH_Attribute::Id);
		else
			$ref = $node->GetAttribute(WH_Attribute::Id);
		$this->document->GetCurrentWord()->SetAttribute(WH_Attribute::Reference, $ref);
	}

	////////////////////////////////////////////////////////////////////////////////
	/**
	 *
	 */
	protected function ParseHiero(&$str, &$parent)
	{
		if($this->ParseOperator($str, "-", $left, $right))
		{
			if((!$parent->IsAttributeSet(WH_Attribute::Operator))
			|| ($parent->GetAttribute(WH_Attribute::Operator) != "-"))
			{
				$block = &$parent->AddChild(WH_CLASS_GROUP);
				$block->SetAttribute(WH_Attribute::Operator, "-");
				$this->ParseHiero($left,  $block);
				$this->ParseHiero($right, $block);
			}
			else
			{
				$this->ParseHiero($left,  $parent);
				$this->ParseHiero($right, $parent);
			}
			return;
		}
		if($this->ParseOperator($str, ":", $left, $right))
		{
			if((!$parent->IsAttributeSet(WH_Attribute::Operator))
			|| ($parent->GetAttribute(WH_Attribute::Operator) != ":"))
			{
				$block = $this->document->AddLayout($parent, WH_OPERATOR_SUBORDINATION);
				$this->ParseHiero($left,  $block);
				$this->ParseHiero($right, $block);
			}
			else
			{
				$this->ParseHiero($left,  $parent);
				$this->ParseHiero($right, $parent);
			}
			return;
		}
		if($this->ParseOperator($str, "*", $left, $right))
		{
			if((!$parent->IsAttributeSet(WH_Attribute::Operator))
			|| ($parent->GetAttribute(WH_Attribute::Operator) != "*"))
			{
				$block = $this->document->AddLayout($parent, WH_OPERATOR_JUXTAPOSITION);
				$this->ParseHiero($left,  $block);
				$this->ParseHiero($right, $block);
			}
			else
			{
				$this->ParseHiero($left,  $parent);
				$this->ParseHiero($right, $parent);
			}
			return;
		}
		if($this->ParseOperator($str, "&", $left, $right))
		{
			if((!$parent->IsAttributeSet(WH_Attribute::Operator))
			|| ($parent->GetAttribute(WH_Attribute::Operator) != "&"))
			{
				$block = $this->document->AddLayout($parent, WH_OPERATOR_LIGATURE);
				$this->ParseHiero($left,  $block);
				$this->ParseHiero($right, $block);
			}
			else
			{
				$this->ParseHiero($left,  $parent);
				$this->ParseHiero($right, $parent);
			}
			return;
		}
		if($this->ParseParenthesis($str, $result))
		{
			$this->ParseHiero($result, $parent);
			return;
		}

		$block = $this->document->AddHiero($parent);
		$this->SetHieroAttribute($block, $str);
		if($this->GetVariable("ParseSyntax"))
			$this->SetHieroSyntax($block);
	}

	////////////////////////////////////////////////////////////////////////////////
	/**
	 *
	 */
	function AddHiero(&$str)
	{
		if($this->flag & WH_MDC_FLAG_OPERATOR)
		{
			$this->ParseHiero($str, $this->document->GetCurrentLine());
		}
		else
		{
			$block = $this->document->AddHiero($this->document->GetCurrentLine());
			$this->SetHieroAttribute($block, $str);
			if($this->GetVariable("ParseSyntax"))
				$this->SetHieroSyntax($block);
		}

		$this->acc = "";
		$this->depth = 0;
		$this->flag = WH_MDC_FLAG_NONE;
	}

	private function IsSeparator($char)
	{
		return $char == ' ' || $char == '_' || ord($char) == 0x09;
	}
	
	////////////////////////////////////////////////////////////////////////////////
	/**
	 *
	 */
	public function &Import(&$text)
	{
		$this->document = new WH_Document();
		$root = $this->document->GetRoot();
		$this->document->AddArea($root, WH_MDC_TEXT_HIEROGLYPH);
		$this->document->AddLine();
		if($this->GetVariable("ParseSyntax"))
		{
			$this->document->EnableSyntax();
			$this->createSection = true;
			$this->createSentence = true;
			$this->createWord = true;
		}
		for($i=0; $i<strlen($text); $i++)
		{
			// check text mode change
			if(($i+1 < strlen($text)) && ($text[$i] == '+'))
			{
				switch($text[$i+1]) // Check for text type modification
				{
					case '+': $change_to = WH_MDC_TEXT_COMMENT; break;
					case 's': $change_to = WH_MDC_TEXT_HIEROGLYPH; break;
					case 't': $change_to = WH_MDC_TEXT_TRANSCRIPTION; break;
					case 'l': $change_to = WH_MDC_TEXT_LATIN_NORMAL; break;
					case 'i': $change_to = WH_MDC_TEXT_LATIN_ITALIC; break;
					case 'b': $change_to = WH_MDC_TEXT_LATIN_BOLD; break;
					case 'g': $change_to = WH_MDC_TEXT_GREEK; break;
					case 'c': $change_to = WH_MDC_TEXT_COPTIC; break;
					default:  $change_to = WH_MDC_TEXT_UNDEFINED; break;
				}
				if($change_to != WH_MDC_TEXT_UNDEFINED) // If text type changed
				{
					if($change_to != $this->document->GetCurrentArea()->GetAttribute(WH_Attribute::Type))
					{
						// If accumulator is not empty, flush data to current area
						$this->FlushAccumulator();
						if($this->document->GetCurrentArea()->GetAttribute(WH_Attribute::Type) == WH_MDC_TEXT_HIEROGLYPH)
							$this->document->AddLine();
						// Create new area
						$this->document->AddArea($root, $change_to);
					}
					$i += 1;
					continue; // skip futher process
				}
			}

			// Parse hieroglyph and
			if($this->document->GetCurrentArea()->GetAttribute(WH_Attribute::Type) == WH_MDC_TEXT_HIEROGLYPH)
			{
				// end of line/page handle
				if($text[$i] == '!')
				{
					if(($i+1 < strlen($text)) && ($text[$i+1] == '!')) // end of page
					{
						if($this->acc != "")
							$this->AddHiero($this->acc);

						if($this->GetVariable("ParseSyntax"))
						{
							$this->createSection = true;
							$this->createSentence = true;
							$this->createWord = true;
						}
						
						$this->document->AddArea($root, WH_MDC_TEXT_HIEROGLYPH);
						$this->document->AddLine();
						$i++;
						continue;
					}
					else // end of line
					{
						if($this->acc != "")
							$this->AddHiero($this->acc);

						if($this->GetVariable("ParseSyntax"))
						{
							$this->createSentence = true;
							$this->createWord = true;
						}
													
						$this->document->AddLine();
						continue;
					}
				}

				// parenthesis
				if($text[$i] == '(')
					$this->depth++;
				if($text[$i] == ')')
					$this->depth--;

				// block separator
				if($this->depth == 0)
				{
					// sentence & word sperator
					if($this->IsSeparator($text[$i])) // space, under_score, tab
					{
						if(($i+1 < strlen($text)) && ($this->IsSeparator($text[$i + 1]))) // end of sentence
						{
							if($this->acc != "")
								$this->AddHiero($this->acc);

							if($this->GetVariable("ParseSyntax"))
							{
								$this->createSentence = true;
								$this->createWord = true;
							}
							
							$i++;

							while(($i+1 < strlen($text)) && ($this->IsSeparator($text[$i + 1])))
								$i++;
						}
						else // end of word
						{
							$temp = $this->acc;

							if($this->acc != "")
								$this->AddHiero($this->acc);

							if($this->GetVariable("ParseSyntax"))
							{
								$this->createWord = true;
							}
						}

						continue;
					}

					// block separator
					if($text[$i] == '-' || $text[$i] == '=' || ord($text[$i]) == 0x0A || ord($text[$i]) == 0x0D) // minus, equal, new_line, return
					{
						if($this->acc != "")
							$this->AddHiero($this->acc);

						continue;
					}
				}

				// check type
				$ascii = ord($text[$i]);
				if($ascii >= ord('0') && $ascii <= ord('9'))
					$this->flag |= WH_MDC_FLAG_NUMBER;
				if(($ascii >= ord('a') && $ascii <= ord('z')) || ($ascii >= ord('A') && $ascii <= ord('Z')) || $ascii == ord('.'))
					$this->flag |= WH_MDC_FLAG_ALPHA;
				if(($ascii == ord(':')) || ($ascii == ord('*')) || ($ascii == ord('&'))|| ($ascii == ord('(')) || ($ascii == ord(')')) || ($ascii == ord('-')))
					$this->flag |= WH_MDC_FLAG_OPERATOR;

				$this->acc .= $text[$i];
			}
			else
			{
				$this->acc .= $text[$i];
			}
		}
		// If accumulator is not empty, flush data to current area
		$this->FlushAccumulator();
		
		sort($root->GetChildren());
		
		return $this->document;
	}
}

?>